/******************************************************************************
 * Product: Adempiere ERP & CRM Smart Business Solution                        *
 * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved.                *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. This program is distributed in the hope   *
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.           *
 * See the GNU General Public License for more details.                       *
 * You should have received a copy of the GNU General Public License along    *
 * with this program; if not, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 * For the text or an alternative of this public license, you may reach us    *
 * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA        *
 * or via info@compiere.org or http://www.compiere.org/license.html           *
 *****************************************************************************/
package org.adempiere.model;

import java.math.BigDecimal;
import java.sql.*;
import java.util.*;
import java.util.logging.Level;

import javax.print.Doc;

import org.compiere.model.MBPartner;
import org.compiere.model.MInOut;
import org.compiere.model.MInOutLine;
import org.compiere.model.MLocator;
import org.compiere.model.MOrder;
import org.compiere.model.MProduct;
import org.compiere.model.MSequence;
import org.compiere.model.MStorage;
import org.compiere.model.MUOMConversion;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.TimeUtil;
import org.compiere.util.Trx;
import org.jboss.util.Strings;
/**
 * 	BarcodeTrx
 *
 *  @author Shindu
 *  @since 1 May 2013
 */
public class MBarcodeTrx extends X_M_BarcodeTrx
{
	/**
	 * 
	 */
	
	/**	Lines					*/
	private MBarcodeTrxLine[]	m_lines = null;
	//
	private static final long serialVersionUID = 1212241234L;
	/**************************************************************************
	 * 	Standard Constructor
	 *	@param ctx context
	 *  @param M_BarcodeTrx_ID master id
	 *	@param trxName trx name
	 */
	public MBarcodeTrx (Properties ctx, int M_BarcodeTrx_ID, String trxName)
	{
		super (ctx, M_BarcodeTrx_ID, trxName);
	}	

	/**
	 *  Load Constructor
	 *  @param ctx context
	 *  @param rs result set record
	 *  @param trxName transaction
	 */
	public MBarcodeTrx (Properties ctx, ResultSet rs, String trxName)
	{
		super(ctx, rs, trxName);
	}	//	MInOutLine

	/**************************************************************************
	 * 	Before Save
	 *	@param newRecord new
	 *	@return save
	 */
	protected boolean beforeSave (boolean newRecord)
	{
		if (getIsSOTrx() && getC_BPartner_ID()==0)
		{
			log.severe("Business Partner is mandatory!");
			return false;
		}
		log.fine("");
		return true;
	}	//	beforeSave
	
	/**
	 * 	Before Delete
	 *	@return true if drafted
	 */
	protected boolean beforeDelete ()
	{
		return true;
	}	//	beforeDelete

	/**
	 * 	String Representation
	 *	@return info
	 */
	public String toString ()
	{
		return "MBarcodeTrx: " 
				+ getM_BarcodeTrx_ID() + "-" 
				+ getM_InOut_ID() + " [" + getScanDate().toString() + "]"   ;
	}	//	toString
		
	protected boolean afterSave (boolean newRecord, boolean success)
	{
		return true;
	}	//	afterSave	
    /*** 
	 *   Add overrides funciton after delete
	 */
	protected boolean afterDelete (boolean success)
	{
		return true;
	}	//	afterDelete
	/**
	 * Get BarcodeTrxLine
	 * @return lines
	 */
	public  MBarcodeTrxLine[] getLines(){
		if (m_lines != null ) {
			set_TrxName(m_lines, get_TrxName());
			return m_lines;
		}
		ArrayList<MBarcodeTrxLine> list = new ArrayList<MBarcodeTrxLine>();
		String sql = "SELECT * FROM M_BarcodeTrxLine WHERE M_BarcodeTrx_ID=? ORDER BY M_BarcodeTrxLine_ID";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try
		{
			pstmt = DB.prepareStatement(sql, get_TrxName());
			pstmt.setInt(1, getM_BarcodeTrx_ID());
			rs = pstmt.executeQuery();
			while (rs.next())
				list.add(new MBarcodeTrxLine(getCtx(), rs, get_TrxName()));
		}
		catch (SQLException ex)
		{
			log.log(Level.SEVERE, sql, ex);
			list = null;
		//	throw new DBException(ex);
		}
		finally
		{
			DB.close(rs, pstmt);
			rs = null; pstmt = null;
		}
		//
		if (list == null)
			return null;
		//
		m_lines = new MBarcodeTrxLine[list.size()];
		list.toArray(m_lines);
		return m_lines;
	}
	
	/**
	 * Generate MInOut and MInOutLine.
	 * @isComplete If true, then document complete after generate
	 * @return MInOut generated
	 */
	public MInOut generateMInOut(boolean isAutoComplete){
		MInOut io ;
		String tmp=Strings.EMPTY;
		log.fine("");
		if (getIsSOTrx()){ //Generat shipment
			io = new MInOut(new MOrder(Env.getCtx(),  getC_Order_ID(), get_TrxName()), 
					getC_DocType_ID() , TimeUtil.getServerTime());
		}else{ //generate Material Receipt
			io = new MInOut(getCtx(), 0, get_TrxName());
			io.setIsSOTrx(getIsSOTrx());
			String movType=MInOut.getMovementTypeByDocumentNo(getC_DocType_ID(), getIsSOTrx());
			io.setMovementType(movType);			
			io.setC_DocType_ID(getC_DocType_ID());
			io.setPOReference(getPOReference());
			//Bpartner
			MBPartner bp= MBPartner.get(getCtx(), getC_BPartner_ID());
			io.setBPartner(bp);
			//locator
			MLocator loc=MLocator.get(getCtx(), getM_Locator_ID());		
			io.setM_Warehouse_ID(loc.getM_Warehouse_ID());
		}
		if (io.getMovementType().contentEquals(MInOut.MOVEMENTTYPE_CustomerShipment)){
			io.setPOReference(MSequence.getDocumentNo(getAD_Client_ID(),  io.get_TableName(),get_TrxName()));
		}		
		io.setDescription("Barcode ID: " + getM_BarcodeTrx_ID());
		io.setMovementDate(getScanDate());
		if (!io.save())
		{
			tmp = "Fail to save Ship/Receipt:'\r\n" + CLogger.retrieveErrorString(null);
			Trx.get(get_TrxName(), false).rollback();
			log.saveInfo("", tmp);
			return null;
		}
		
		/*get lines */
		String sql = Strings.EMPTY; 
		if (getIsSOTrx()){ //Query untuk generate MInOut by Order
			sql= "SELECT M_Product_ID, SUM(qty) as Qty, C_UOM_ID, C_OrderLine_ID " +
					" FROM M_BarcodeTrxLine WHERE M_BarcodeTrx_ID=? " +
					"GROUP BY M_Product_ID, C_UOM_ID, C_OrderLine_ID ";
		}else{ //Query untuk generate Product Receipt
			sql= "SELECT M_Product_ID, SUM(qty) as Qty, C_UOM_ID " +
					" FROM M_BarcodeTrxLine WHERE M_BarcodeTrx_ID=? " +
					"GROUP BY M_Product_ID, C_UOM_ID ";
		}
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		int C_OrderLine_ID=0;
		try
		{
			pstmt = DB.prepareStatement(sql, get_TrxName());
			pstmt.setInt(1, getM_BarcodeTrx_ID());
			rs = pstmt.executeQuery();
			while (rs.next()){
				MInOutLine iol = new MInOutLine(io);
				MProduct prod = MProduct.get(p_ctx, rs.getInt("M_Product_ID"));
				iol.setProduct(prod);				
				iol.setM_Locator_ID(getM_Locator_ID());
				iol.setQty(rs.getBigDecimal("Qty"));
				if (getIsSOTrx()){ //Jika SO, 					
					//get stok
					BigDecimal stok[]= MStorage.getQty(prod.getM_Product_ID(), getM_Locator_ID());
					//set QTY
					iol.set_ValueOfColumn("avai", stok[0]);
					iol.set_ValueOfColumn("stok", stok[1]);
					iol.set_ValueOfColumn("rdqty", stok[2]);
					iol.set_ValueOfColumn("qtypackage", 
							 MUOMConversion.convertProductFrom(p_ctx, 
										prod.getM_Product_ID(),
										Env.getContextAsInt(p_ctx, "#Def_Package_UOM_ID"), 
										Env.ONE));
					C_OrderLine_ID= rs.getInt("C_OrderLine_ID");
					iol.setC_OrderLine_ID(C_OrderLine_ID);					
				}			
				//				
				if (!iol.save()){			
					log.saveError("", "Fail to save Ship/Receipt:\r\n" +
									prod.getUPC() + "-" +  prod.getName() + "\r\n" + CLogger.retrieveErrorString(null) );	
					Trx.get(get_TrxName(), false).rollback();
					return null;
				}
				//update MBarodeTrxLine
				if (!MBarcodeTrxLine.updateMInoutLineID(get_TrxName(), 
						iol.getM_InOutLine_ID(), getM_BarcodeTrx_ID(), 
						iol.getM_Product_ID(), rs.getInt("C_UOM_ID"), C_OrderLine_ID)){					
					log.saveError("", "Fail to update Barcode Line:\r\n" 
									 + prod.getUPC() + "-"	+ prod.getName() + "\r\n" + CLogger.retrieveErrorString(null) );
					Trx.get(get_TrxName(), false).rollback();
					return null;
				}
					
			}			
			setM_InOut_ID(io.getM_InOut_ID());			
			setIsGeneratedToInOut(true);
			save();
			//try complete io if outcomplete
			if (isAutoComplete){				
				if (!io.processIt(MInOut.DOCSTATUS_Completed)){
					log.saveError("", "Fail to Complete MInOut: " + io.getDocStatus() + " \r\n" 
							  + CLogger.retrieveErrorString(null) );
					Trx.get(get_TrxName(), false).rollback();
					return null;
				}
			}
			io.save();
			Trx.get(get_TrxName(), false).commit();
			return io;
		}
		catch (SQLException ex)
		{
			log.log(Level.SEVERE, ex.getMessage());
		//	throw new DBException(ex);
		}
		catch(IllegalArgumentException ex2){
			log.log(Level.SEVERE, ex2.getMessage());
		}
		finally
		{
			DB.close(rs, pstmt);
			rs = null; pstmt = null;
		}
		Trx.get(get_TrxName(), false).rollback();
		return null;		
	}
	/***
	 * Cancel barcode transaction. 
	 * Set barcode line to Void
	 * @return true/false
	 */
	public boolean cancelBarcode(){
		boolean result=false;
		String sql;
		sql= "UPDATE M_BarcodeTrxLine SET DocStatus = '" + MBarcodeTrxLine.DOCACTION_Void + "' " +
			 "WHERE M_BarcodeTrx_ID = " + getM_BarcodeTrx_ID()	;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try
		{
			pstmt = DB.prepareStatement(sql, get_TrxName());
			pstmt.execute();
			result=true;
			//		
		}
		catch (SQLException ex)
		{					
			result=false;
			log.saveError("", "Fail to update Barcode Line:\r\n" + ex.getMessage() );			
		}
		finally
		{
			DB.close(rs, pstmt);
			rs = null; pstmt = null;
		}
		return result;
	}
		
}	
